package com.kuangjia.student_ems.service.impl;

import com.kuangjia.student_ems.dto.AttendanceDTO;
import com.kuangjia.student_ems.dto.AttendanceStatisticsDTO;
import com.kuangjia.student_ems.dto.request.AttendanceRequest;
import com.kuangjia.student_ems.dto.request.AttendanceLocationRequest;
import com.kuangjia.student_ems.entity.Attendance;
import com.kuangjia.student_ems.entity.AttendanceLocation;
import com.kuangjia.student_ems.entity.User;
import com.kuangjia.student_ems.exception.ResourceNotFoundException;
import com.kuangjia.student_ems.repository.AttendanceRepository;
import com.kuangjia.student_ems.repository.AttendanceMapper;
import com.kuangjia.student_ems.repository.AttendanceLocationRepository;
import com.kuangjia.student_ems.repository.UserRepository;
import com.kuangjia.student_ems.service.AttendanceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class AttendanceServiceImpl implements AttendanceService {
    
    private final AttendanceRepository attendanceRepository;
    private final UserRepository userRepository;
    
    @Autowired
    private AttendanceMapper attendanceMapper;
    
    @Autowired
    private AttendanceLocationRepository attendanceLocationRepository;
    
    @Autowired
    public AttendanceServiceImpl(AttendanceRepository attendanceRepository, UserRepository userRepository) {
        this.attendanceRepository = attendanceRepository;
        this.userRepository = userRepository;
    }
    
    @Override
    @Transactional
    public AttendanceDTO clockIn(Long userId) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new ResourceNotFoundException("用户", "id", userId));
        
        LocalDate today = LocalDate.now();
        LocalDateTime now = LocalDateTime.now();
        
        // 查找今天的考勤记录
        QueryWrapper<Attendance> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(Attendance::getUserId, userId)
                .eq(Attendance::getDate, today);
        Attendance attendance = attendanceMapper.selectOne(wrapper);
        
        if (attendance == null) {
            // 新建考勤记录
            attendance = new Attendance();
            attendance.setUserId(userId);
            attendance.setDate(today);
            attendance.setCheckInTime(now);
            
            // 判断是否迟到（假设9点为正常上班时间）
            if (now.getHour() >= 9 && now.getMinute() > 0) {
                attendance.setStatus(Attendance.AttendanceStatus.LATE);
            } else {
                attendance.setStatus(Attendance.AttendanceStatus.NORMAL);
            }
        } else {
            // 更新已有记录，允许多次打卡
            attendance.setCheckInTime(now);
            
            // 判断是否迟到
            if (now.getHour() >= 9 && now.getMinute() > 0) {
                attendance.setStatus(Attendance.AttendanceStatus.LATE);
            } else if (attendance.getStatus() != Attendance.AttendanceStatus.LEAVE) {
                attendance.setStatus(Attendance.AttendanceStatus.NORMAL);
            }
            
            // 添加备注，记录重复打卡，并限制长度
            String remark = attendance.getRemark();
            String nowStr = now.toString();
            if (remark == null || remark.isEmpty()) {
                attendance.setRemark("重复签到时间: " + nowStr);
            } else {
                String newRemark = remark + "; 重复签到时间: " + nowStr;
                attendance.setRemark(limitRemarkLength(newRemark, 200)); // 限制长度为200字符
            }
        }
        
        if (attendance.getId() == null) {
            attendanceMapper.insert(attendance);
        } else {
            attendanceMapper.updateById(attendance);
        }
        
        return convertToDTO(attendance);
    }
    
    @Override
    @Transactional
    public AttendanceDTO clockOut(Long userId) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new ResourceNotFoundException("用户", "id", userId));
        
        LocalDate today = LocalDate.now();
        LocalDateTime now = LocalDateTime.now();
        
        // 查找今天的考勤记录
        QueryWrapper<Attendance> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(Attendance::getUserId, userId)
                .eq(Attendance::getDate, today);
        Attendance attendance = attendanceMapper.selectOne(wrapper);
        
        // 如果没有找到考勤记录，判断是否要自动补签
        if (attendance == null) {
            // 自动补签，创建一个新的考勤记录
            attendance = new Attendance();
            attendance.setUserId(userId);
            attendance.setDate(today);
            attendance.setCheckInTime(now); // 以当前时间作为签到时间
            attendance.setStatus(Attendance.AttendanceStatus.LATE); // 标记为迟到
            attendance.setRemark("系统自动补签 - 签退时无签到记录"); // 添加备注
        }

        // 只允许第一次签退有效，后续签退直接返回
        if (attendance.getCheckOutTime() != null) {
            return convertToDTO(attendance);
        }

        // 第一次签退，正常处理
        attendance.setCheckOutTime(now);
        // 判断是否早退（假设18点为正常下班时间）
        if (now.getHour() < 18 && attendance.getStatus() != Attendance.AttendanceStatus.LEAVE) {
            attendance.setStatus(Attendance.AttendanceStatus.EARLY_LEAVE);
        }
        // 不再追加remark
        if (attendance.getId() == null) {
            attendanceMapper.insert(attendance);
        } else {
            attendanceMapper.updateById(attendance);
        }
        return convertToDTO(attendance);
    }
    
    @Override
    @Transactional
    public AttendanceDTO createAttendance(Long userId, AttendanceRequest request) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new ResourceNotFoundException("用户", "id", userId));
        
        // 检查该日期是否已存在考勤记录
        QueryWrapper<Attendance> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(Attendance::getUserId, userId)
                .eq(Attendance::getDate, request.getDate());
        Attendance existingAttendance = attendanceMapper.selectOne(wrapper);
        
        if (existingAttendance != null) {
            throw new IllegalArgumentException("该用户在该日期已有考勤记录");
        }
        
        Attendance attendance = new Attendance();
        attendance.setUserId(userId);
        attendance.setDate(request.getDate());
        
        // 将LocalTime转换为LocalDateTime
        if (request.getCheckInTime() != null) {
            attendance.setCheckInTime(LocalDateTime.of(request.getDate(), request.getCheckInTime()));
        }
        
        if (request.getCheckOutTime() != null) {
            attendance.setCheckOutTime(LocalDateTime.of(request.getDate(), request.getCheckOutTime()));
        }
        
        attendance.setStatus(request.getStatus());
        attendance.setRemark(request.getRemark());
        
        attendanceMapper.insert(attendance);
        return convertToDTO(attendance);
    }
    
    @Override
    @Transactional
    public AttendanceDTO updateAttendance(Long attendanceId, AttendanceRequest request) {
        Attendance attendance = attendanceMapper.selectById(attendanceId);
        if (attendance == null) {
            throw new ResourceNotFoundException("考勤记录", "id", attendanceId);
        }
        
        attendance.setDate(request.getDate());
        
        // 将LocalTime转换为LocalDateTime
        if (request.getCheckInTime() != null) {
            attendance.setCheckInTime(LocalDateTime.of(request.getDate(), request.getCheckInTime()));
        } else {
            attendance.setCheckInTime(null);
        }
        
        if (request.getCheckOutTime() != null) {
            attendance.setCheckOutTime(LocalDateTime.of(request.getDate(), request.getCheckOutTime()));
        } else {
            attendance.setCheckOutTime(null);
        }
        
        attendance.setStatus(request.getStatus());
        attendance.setRemark(request.getRemark());
        
        attendanceMapper.updateById(attendance);
        return convertToDTO(attendance);
    }
    
    @Override
    @Transactional
    public void deleteAttendance(Long attendanceId) {
        Attendance attendance = attendanceMapper.selectById(attendanceId);
        if (attendance == null) {
            throw new ResourceNotFoundException("考勤记录", "id", attendanceId);
        }
        attendanceMapper.deleteById(attendanceId);
    }
    
    @Override
    public AttendanceDTO getAttendanceById(Long attendanceId) {
        Attendance attendance = attendanceMapper.selectById(attendanceId);
        if (attendance == null) {
            throw new ResourceNotFoundException("考勤记录", "id", attendanceId);
        }
        return convertToDTO(attendance);
    }
    
    @Override
    public AttendanceDTO getAttendanceByUserAndDate(Long userId, LocalDate date) {
        // 使用MyBatis-Plus查询
        QueryWrapper<Attendance> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(Attendance::getUserId, userId)
                .eq(Attendance::getDate, date);
        Attendance attendance = attendanceMapper.selectOne(wrapper);
        
        if (attendance == null) {
            throw new ResourceNotFoundException("考勤记录", "userId和date", userId + "," + date);
        }
        
        return convertToDTO(attendance);
    }
    
    @Override
    public List<AttendanceDTO> getAttendancesByUser(Long userId) {
        // 使用MyBatis-Plus查询，按日期降序排列
        QueryWrapper<Attendance> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(Attendance::getUserId, userId)
                .orderByDesc(Attendance::getDate)
                .orderByDesc(Attendance::getCreateTime);
        List<Attendance> attendances = attendanceMapper.selectList(wrapper);
        return attendances.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }
    
    @Override
    public List<AttendanceDTO> getAttendancesByUserAndDateRange(Long userId, LocalDate startDate, LocalDate endDate) {
        // 使用MyBatis-Plus查询，按日期降序排列
        QueryWrapper<Attendance> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(Attendance::getUserId, userId)
                .ge(Attendance::getDate, startDate)
                .le(Attendance::getDate, endDate)
                .orderByDesc(Attendance::getDate)
                .orderByDesc(Attendance::getCreateTime);
        List<Attendance> attendances = attendanceMapper.selectList(wrapper);
        return attendances.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }
    
    @Override
    public List<AttendanceDTO> getAttendancesByDepartmentAndDateRange(Long departmentId, LocalDate startDate, LocalDate endDate) {
        // 先获取部门下的所有用户
        List<User> users = userRepository.findByDepartmentId(departmentId);
        List<Long> userIds = users.stream().map(User::getId).collect(Collectors.toList());
        
        if (userIds.isEmpty()) {
            return new ArrayList<>();
        }
        
        // 使用MyBatis-Plus查询，按日期降序排列
        QueryWrapper<Attendance> wrapper = new QueryWrapper<>();
        wrapper.lambda().in(Attendance::getUserId, userIds)
                .ge(Attendance::getDate, startDate)
                .le(Attendance::getDate, endDate)
                .orderByDesc(Attendance::getDate)
                .orderByDesc(Attendance::getCreateTime);
        List<Attendance> attendances = attendanceMapper.selectList(wrapper);
        return attendances.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }
    
    @Override
    public AttendanceStatisticsDTO getUserAttendanceStatistics(Long userId, LocalDate startDate, LocalDate endDate) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new ResourceNotFoundException("用户", "id", userId));
        
        // 使用MyBatis-Plus查询
        QueryWrapper<Attendance> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(Attendance::getUserId, userId)
                .ge(Attendance::getDate, startDate)
                .le(Attendance::getDate, endDate)
                .orderByDesc(Attendance::getDate)
                .orderByDesc(Attendance::getCreateTime);
        List<Attendance> attendances = attendanceMapper.selectList(wrapper);
        
        Map<Attendance.AttendanceStatus, Long> statusCount = getStatusCount(attendances);
        
        AttendanceStatisticsDTO statistics = new AttendanceStatisticsDTO();
        statistics.setUserId(userId);
        statistics.setUserName(user.getName());
        if (user.getDepartment() != null) {
            statistics.setDepartmentName(user.getDepartment().getName());
        }
        statistics.setNormalDays(statusCount.getOrDefault(Attendance.AttendanceStatus.NORMAL, 0L));
        statistics.setLateDays(statusCount.getOrDefault(Attendance.AttendanceStatus.LATE, 0L));
        statistics.setEarlyLeaveDays(statusCount.getOrDefault(Attendance.AttendanceStatus.EARLY_LEAVE, 0L));
        statistics.setAbsentDays(statusCount.getOrDefault(Attendance.AttendanceStatus.ABSENT, 0L));
        statistics.setLeaveDays(statusCount.getOrDefault(Attendance.AttendanceStatus.LEAVE, 0L));
        statistics.calculateTotalDays();
        
        return statistics;
    }
    
    @Override
    public List<AttendanceStatisticsDTO> getDepartmentAttendanceStatistics(Long departmentId, LocalDate startDate, LocalDate endDate) {
        List<User> users = userRepository.findByDepartmentId(departmentId);
        return users.stream()
                .map(user -> getUserAttendanceStatistics(user.getId(), startDate, endDate))
                .collect(Collectors.toList());
    }
    
    @Override
    public Map<Attendance.AttendanceStatus, Long> getAttendanceStatusCount(Long userId, LocalDate startDate, LocalDate endDate) {
        // 使用MyBatis-Plus查询
        QueryWrapper<Attendance> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(Attendance::getUserId, userId)
                .ge(Attendance::getDate, startDate)
                .le(Attendance::getDate, endDate)
                .orderByDesc(Attendance::getDate)
                .orderByDesc(Attendance::getCreateTime);
        List<Attendance> attendances = attendanceMapper.selectList(wrapper);
        return getStatusCount(attendances);
    }
    
    @Override
    public List<AttendanceDTO> getAllAttendances() {
        // 使用MyBatis-Plus查询，按日期降序排列
        QueryWrapper<Attendance> wrapper = new QueryWrapper<>();
        wrapper.lambda().orderByDesc(Attendance::getDate).orderByDesc(Attendance::getCreateTime);
        List<Attendance> attendances = attendanceMapper.selectList(wrapper);
        return attendances.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }
    
    @Override
    public List<AttendanceDTO> searchAttendances(String keyword) {
        if (keyword == null || keyword.trim().isEmpty()) {
            return getAllAttendances();
        }
        
        // 使用MyBatis-Plus查询，支持关键词搜索并按日期降序排列
        QueryWrapper<Attendance> wrapper = new QueryWrapper<>();
        wrapper.lambda().like(Attendance::getRemark, keyword)
                .orderByDesc(Attendance::getDate)
                .orderByDesc(Attendance::getCreateTime);
        List<Attendance> attendances = attendanceMapper.selectList(wrapper);
        return attendances.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }
    
    @Override
    public IPage<AttendanceDTO> getAttendancePage(Page<Attendance> page, String keyword, Long userId, LocalDate startDate, LocalDate endDate, String sortField, String sortOrder) {
        try {
            QueryWrapper<Attendance> wrapper = new QueryWrapper<>();
            
            // 关键词搜索（员工姓名）
            if (keyword != null && !keyword.isEmpty()) {
                // 这里需要通过用户表关联查询，暂时用简单的方式
                wrapper.lambda().like(Attendance::getRemark, keyword);
            }
            
            // 按用户ID筛选
            if (userId != null) {
                wrapper.lambda().eq(Attendance::getUserId, userId);
            }
            
            // 按日期范围筛选
            if (startDate != null) {
                wrapper.lambda().ge(Attendance::getDate, startDate);
            }
            if (endDate != null) {
                wrapper.lambda().le(Attendance::getDate, endDate);
            }
            
            // 排序处理
            if (sortField != null && !sortField.isEmpty()) {
                boolean isAsc = "asc".equalsIgnoreCase(sortOrder);
                switch (sortField.toLowerCase()) {
                    case "date":
                        wrapper.lambda().orderBy(true, isAsc, Attendance::getDate);
                        break;
                    case "checkintime":
                        wrapper.lambda().orderBy(true, isAsc, Attendance::getCheckInTime);
                        break;
                    case "checkouttime":
                        wrapper.lambda().orderBy(true, isAsc, Attendance::getCheckOutTime);
                        break;
                    case "status":
                        wrapper.lambda().orderBy(true, isAsc, Attendance::getStatus);
                        break;
                    case "createtime":
                        wrapper.lambda().orderBy(true, isAsc, Attendance::getCreateTime);
                        break;
                    default:
                        // 默认按日期降序，创建时间降序
                        wrapper.lambda().orderByDesc(Attendance::getDate).orderByDesc(Attendance::getCreateTime);
                        break;
                }
            } else {
                // 默认按日期降序，创建时间降序 - 显示最近的考勤记录
                wrapper.lambda().orderByDesc(Attendance::getDate).orderByDesc(Attendance::getCreateTime);
            }
            
            IPage<Attendance> attendancePage = attendanceMapper.selectPage(page, wrapper);
            IPage<AttendanceDTO> dtoPage = attendancePage.convert(this::convertToDTO);
            return dtoPage;
        } catch (Exception e) {
            System.err.println("考勤分页查询异常: " + e.getMessage());
            e.printStackTrace();
            throw e;
        }
    }
    
    @Override
    @Transactional
    public AttendanceDTO clockInWithLocation(Long userId, AttendanceLocationRequest request) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new ResourceNotFoundException("用户", "id", userId));
        LocalDate today = LocalDate.now();
        LocalDateTime now = LocalDateTime.now();
        // 查找今天的考勤记录
        QueryWrapper<Attendance> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(Attendance::getUserId, userId)
                .eq(Attendance::getDate, today);
        Attendance attendance = attendanceMapper.selectOne(wrapper);
        if (attendance == null) {
            attendance = new Attendance();
            attendance.setUserId(userId);
            attendance.setDate(today);
            attendance.setCheckInTime(now);
            if (now.getHour() >= 9 && now.getMinute() > 0) {
                attendance.setStatus(Attendance.AttendanceStatus.LATE);
            } else {
                attendance.setStatus(Attendance.AttendanceStatus.NORMAL);
            }
            attendanceMapper.insert(attendance);
        } else {
            attendance.setCheckInTime(now);
            if (now.getHour() >= 9 && now.getMinute() > 0) {
                attendance.setStatus(Attendance.AttendanceStatus.LATE);
            } else if (attendance.getStatus() != Attendance.AttendanceStatus.LEAVE) {
                attendance.setStatus(Attendance.AttendanceStatus.NORMAL);
            }
            attendanceMapper.updateById(attendance);
        }
        // 保存位置记录
        AttendanceLocation location = new AttendanceLocation();
        location.setAttendanceId(attendance.getId());
        location.setUserId(userId);
        location.setDate(today);
        location.setLocationType(AttendanceLocation.LocationType.CHECK_IN);
        location.setLatitude(request.getLatitude());
        location.setLongitude(request.getLongitude());
        location.setLocationName(request.getLocation());
        location.setAddress(request.getAddress());
        location.setAccuracy(request.getAccuracy());
        if (request.getLocationSource() != null) {
            location.setLocationSource(AttendanceLocation.LocationSource.valueOf(request.getLocationSource().name()));
        } else {
            location.setLocationSource(AttendanceLocation.LocationSource.GPS);
        }
        location.setLocationTime(now);
        attendanceLocationRepository.save(location);
        return convertToDTO(attendance);
    }
    
    @Override
    @Transactional
    public AttendanceDTO clockOutWithLocation(Long userId, AttendanceLocationRequest request) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new ResourceNotFoundException("用户", "id", userId));
        LocalDate today = LocalDate.now();
        LocalDateTime now = LocalDateTime.now();
        // 查找今天的考勤记录
        QueryWrapper<Attendance> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(Attendance::getUserId, userId)
                .eq(Attendance::getDate, today);
        Attendance attendance = attendanceMapper.selectOne(wrapper);
        if (attendance == null) {
            throw new ResourceNotFoundException("考勤记录", "userId+date", userId + "+" + today);
        }
        attendance.setCheckOutTime(now);
        attendanceMapper.updateById(attendance);
        // 保存签退位置记录
        AttendanceLocation location = new AttendanceLocation();
        location.setAttendanceId(attendance.getId());
        location.setUserId(userId);
        location.setDate(today);
        location.setLocationType(AttendanceLocation.LocationType.CHECK_OUT);
        location.setLatitude(request.getLatitude());
        location.setLongitude(request.getLongitude());
        location.setLocationName(request.getLocation());
        location.setAddress(request.getAddress());
        location.setAccuracy(request.getAccuracy());
        if (request.getLocationSource() != null) {
            location.setLocationSource(AttendanceLocation.LocationSource.valueOf(request.getLocationSource().name()));
        } else {
            location.setLocationSource(AttendanceLocation.LocationSource.GPS);
        }
        location.setLocationTime(now);
        attendanceLocationRepository.save(location);
        return convertToDTO(attendance);
    }
    
    private Map<Attendance.AttendanceStatus, Long> getStatusCount(List<Attendance> attendances) {
        Map<Attendance.AttendanceStatus, Long> statusCount = new HashMap<>();
        
        for (Attendance attendance : attendances) {
            Attendance.AttendanceStatus status = attendance.getStatus();
            statusCount.put(status, statusCount.getOrDefault(status, 0L) + 1);
        }
        
        return statusCount;
    }
    
    private AttendanceDTO convertToDTO(Attendance attendance) {
        AttendanceDTO dto = new AttendanceDTO();
        dto.setId(attendance.getId());
        
        if (attendance.getUser() != null) {
            dto.setUserId(attendance.getUser().getId());
            dto.setUserName(attendance.getUser().getName());
            if (attendance.getUser().getDepartment() != null) {
                dto.setDepartmentId(attendance.getUser().getDepartment().getId());
                dto.setDepartmentName(attendance.getUser().getDepartment().getName());
            }
        } else if (attendance.getUserId() != null) {
            dto.setUserId(attendance.getUserId());
            // 通过userId查询用户信息
            try {
                User user = userRepository.findById(attendance.getUserId()).orElse(null);
                if (user != null) {
                    dto.setUserName(user.getName());
                    if (user.getDepartment() != null) {
                        dto.setDepartmentId(user.getDepartment().getId());
                        dto.setDepartmentName(user.getDepartment().getName());
                    }
                } else {
                    dto.setUserName("未知用户");
                }
            } catch (Exception e) {
                dto.setUserName("未知用户");
            }
        }
        
        dto.setDate(attendance.getDate());
        dto.setCheckInTime(attendance.getCheckInTime());
        dto.setCheckOutTime(attendance.getCheckOutTime());
        dto.setStatus(attendance.getStatus());
        dto.setRemark(attendance.getRemark());
        dto.setCreateTime(attendance.getCreateTime());
        
        return dto;
    }
    
    // 添加一个辅助方法来限制备注字符串长度
    private String limitRemarkLength(String remark, int maxLength) {
        if (remark == null) return null;
        if (remark.length() <= maxLength) return remark;
        
        // 保留最新的记录，删除较早的记录
        String[] parts = remark.split("; ");
        StringBuilder sb = new StringBuilder();
        
        // 从最新的记录开始添加，直到即将超过长度限制
        for (int i = parts.length - 1; i >= 0; i--) {
            if (sb.length() + parts[i].length() + (sb.length() > 0 ? 2 : 0) > maxLength) {
                break;
            }
            
            if (sb.length() > 0) {
                sb.insert(0, "; ");
            }
            sb.insert(0, parts[i]);
        }
        
        return sb.toString();
    }
} 